package com.varian.log.aspect;

import cn.hutool.core.thread.GlobalThreadPool;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.varian.log.util.LogUtil;
import com.varian.tool.Func;
import com.varian.tool.result.IR;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.util.stream.IntStream;

/**
 * @author ben
 * @since 2024/7/22
 */
@Aspect
public class ApiLogAspect {

    @Pointcut("@annotation(com.varian.log.annotation.ApiLog)")
    public void annotationPointcut() {
    }

    @Pointcut("execution(com.varian.tool.result.* *(..))")
    public void methodPointcut() {
    }

    @Pointcut("methodPointcut() && annotationPointcut()")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String requestLocal = signature.getDeclaringTypeName() + "#" + signature.getName();
        HttpServletRequest request = Func.getServletRequest();
        Long userId = LogUtil.getUserId();
        String requestPayload = composeRequestPayload(signature.getParameterNames(), joinPoint.getArgs());
        try {
            IR result = (IR) joinPoint.proceed();
            GlobalThreadPool.execute(() -> LogUtil.apiLog(request, requestLocal, requestPayload, result, userId));
            return result;
        } catch (Exception e) {
            LogUtil.apiErrorLogPre(request, requestLocal, requestPayload, userId);
            throw e;
        }
    }



    private String composeRequestPayload(String[] parameterNames, Object[] args) {
        if (ArrayUtil.isEmpty(parameterNames)) {
            return StrUtil.EMPTY;
        }
        JSONObject obj = JSONUtil.createObj();
        IntStream.range(0, parameterNames.length).boxed().forEach(i -> obj.set(parameterNames[i], args[i]));
        return obj.toString();
    }

}
